/**
 * 3D模型查看器组件
 * 使用Three.js的WebGLRenderer实现3D模型的交互式展示
 * H5环境：使用标准 Three.js
 * 小程序环境：使用 threejs-miniprogram 适配版本
 */

import { useEffect, useRef, useState } from 'react'
import { View, Canvas } from '@tarojs/components'
import Taro from '@tarojs/taro'
import type { ModelConfig, LightConfig } from '../../types/artifact'
import './index.scss'

// 动态导入Three.js
let THREE: any = null
let OrbitControlsClass: any = null
let GLTFLoader: any = null
let createScopedThreejs: any = null

if (process.env.TARO_ENV === 'h5') {
  // H5环境：使用标准 Three.js
  try {
    THREE = require('three')
    const { OrbitControls } = require('three/examples/jsm/controls/OrbitControls')
    const { GLTFLoader: GLTFLoaderClass } = require('three/examples/jsm/loaders/GLTFLoader')
    OrbitControlsClass = OrbitControls
    GLTFLoader = GLTFLoaderClass
    console.log('H5环境：加载标准 Three.js 和 GLTFLoader')
  } catch (e) {
    console.warn('Three.js加载失败', e)
  }
} else if (process.env.TARO_ENV === 'weapp') {
  // 小程序环境：使用适配版本
  try {
    const threejsMiniprogram = require('threejs-miniprogram')
    createScopedThreejs = threejsMiniprogram.createScopedThreejs
    console.log('小程序环境：加载 threejs-miniprogram 适配版本')
  } catch (e) {
    console.warn('threejs-miniprogram 加载失败:', e)
  }
}

interface ModelViewerProps {
  modelConfig: ModelConfig
  lightConfigs: LightConfig[]
  selectedLightId?: string
}

const ModelViewer: React.FC<ModelViewerProps> = ({ 
  modelConfig, 
  lightConfigs,
  selectedLightId 
}) => {
  const containerRef = useRef<HTMLDivElement>(null)
  const canvasId = 'webgl-' + Math.random().toString(36).slice(2, 9)
  const sceneRef = useRef<any>(null)
  const cameraRef = useRef<any>(null)
  const rendererRef = useRef<any>(null)
  const controlsRef = useRef<any>(null)
  const modelRef = useRef<any>(null)
  const lightsRef = useRef<Map<string, any>>(new Map())
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState<string>('')

  // 初始化Three.js场景（H5环境）
  useEffect(() => {
    if (process.env.TARO_ENV !== 'h5' || !THREE) {
      return
    }
    
    if (!containerRef.current) return

    try {
      // 创建场景
      const scene = new THREE.Scene()
      scene.background = new THREE.Color(0xf5f0e8)
      sceneRef.current = scene

      // 创建相机
      const camera = new THREE.PerspectiveCamera(
        45,
        containerRef.current.clientWidth / containerRef.current.clientHeight,
        0.1,
        1000
      )
      camera.position.set(5, 5, 5)
      cameraRef.current = camera

      // 创建WebGL渲染器（高质量配置）
      const renderer = new THREE.WebGLRenderer({
        antialias: true,           // 抗锯齿
        alpha: true,                // 支持透明背景
        powerPreference: 'high-performance',  // 高性能模式
        precision: 'highp',         // 高精度着色器
        stencil: true,             // 启用模板缓冲
        depth: true,               // 启用深度缓冲
        logarithmicDepthBuffer: false  // 标准深度缓冲（更好的性能）
      })
      
      // 设置渲染器尺寸和像素比
      renderer.setSize(containerRef.current.clientWidth, containerRef.current.clientHeight)
      renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)) // 限制最大像素比为2以优化性能
      
      // 配置色彩管理
      renderer.outputColorSpace = THREE.SRGBColorSpace
      renderer.toneMapping = THREE.ACESFilmicToneMapping
      renderer.toneMappingExposure = 1.0
      
      // 配置阴影映射
      renderer.shadowMap.enabled = true
      renderer.shadowMap.type = THREE.PCFSoftShadowMap  // 柔和阴影
      renderer.shadowMap.autoUpdate = true
      
      // 物理正确的光照
      renderer.useLegacyLights = false
      
      containerRef.current.appendChild(renderer.domElement)
      rendererRef.current = renderer

      // 创建控制器
      const controls = new OrbitControlsClass(camera, renderer.domElement)
      controls.enableDamping = true
      controls.dampingFactor = 0.05
      controls.screenSpacePanning = false
      controls.minDistance = 2
      controls.maxDistance = 10
      controls.maxPolarAngle = Math.PI / 2
      controlsRef.current = controls

      // 添加灯光
      setupLights(scene)

      // 添加环境贴图（提升WebGL渲染质量）
      const pmremGenerator = new THREE.PMREMGenerator(renderer)
      pmremGenerator.compileEquirectangularShader()
      
      // 添加地平面（接收阴影）
      const planeGeometry = new THREE.PlaneGeometry(10, 10)
      const planeMaterial = new THREE.ShadowMaterial({ 
        opacity: 0.2,
        side: THREE.FrontSide
      })
      const plane = new THREE.Mesh(planeGeometry, planeMaterial)
      plane.rotation.x = -Math.PI / 2
      plane.position.y = -1
      plane.receiveShadow = true
      scene.add(plane)

      // 加载3D模型
      loadModel(scene)

      // 优化的渲染循环
      let animationFrameId: number
      const animate = () => {
        animationFrameId = requestAnimationFrame(animate)
        
        // 更新控制器
        controls.update()
        
        // 使用WebGLRenderer渲染场景
        renderer.render(scene, camera)
      }
      animate()
      
      console.log('WebGLRenderer初始化完成:', {
        capabilities: renderer.capabilities,
        maxTextureSize: renderer.capabilities.maxTextureSize,
        maxAnisotropy: renderer.capabilities.getMaxAnisotropy(),
        precision: renderer.capabilities.precision
      })

      // 窗口大小变化处理
      const handleResize = () => {
        if (!containerRef.current || !camera || !renderer) return
        camera.aspect = containerRef.current.clientWidth / containerRef.current.clientHeight
        camera.updateProjectionMatrix()
        renderer.setSize(containerRef.current.clientWidth, containerRef.current.clientHeight)
      }
      window.addEventListener('resize', handleResize)

      return () => {
        window.removeEventListener('resize', handleResize)
        
        // 停止动画循环
        if (animationFrameId) {
          cancelAnimationFrame(animationFrameId)
        }
        
        // 清理WebGLRenderer资源
        if (renderer) {
          renderer.dispose()
          renderer.forceContextLoss()
        }
        
        // 清理控制器
        if (controls) {
          controls.dispose()
        }
        
        // 清理场景中的几何体和材质
        if (scene) {
          scene.traverse((object: any) => {
            if (object.isMesh) {
              const mesh = object
              mesh.geometry?.dispose()
              if (Array.isArray(mesh.material)) {
                mesh.material.forEach((material: any) => material.dispose())
              } else {
                mesh.material?.dispose()
              }
            }
          })
        }
        
        console.log('WebGLRenderer资源已清理')
      }
    } catch (err) {
      console.error('初始化3D场景失败:', err)
      setError('3D引擎初始化失败')
      setLoading(false)
    }
  }, [])

  // 初始化Three.js场景（小程序环境）
  useEffect(() => {
    if (process.env.TARO_ENV !== 'weapp' || !createScopedThreejs) {
      if (process.env.TARO_ENV === 'weapp') {
        setLoading(false)
      }
      return
    }

    const initMiniprogram = async () => {
      try {
        // 获取 canvas 节点
        const query = Taro.createSelectorQuery()
        query
          .select(`#${canvasId}`)
          .node()
          .exec((res) => {
            if (!res || !res[0]) {
              console.error('无法获取 canvas 节点')
              setError('Canvas初始化失败')
              setLoading(false)
              return
            }

            const canvas = res[0].node
            
            // 创建与 canvas 绑定的 Three.js 实例
            THREE = createScopedThreejs(canvas)
            console.log('小程序 THREE 实例创建成功')

            // 设置 canvas 尺寸
            const info = Taro.getSystemInfoSync()
            const dpr = info.pixelRatio
            const width = info.windowWidth
            const height = Math.min(info.windowHeight * 0.6, 500)
            
            canvas.width = width * dpr
            canvas.height = height * dpr

            // 创建场景
            const scene = new THREE.Scene()
            scene.background = new THREE.Color(0xf5f0e8)
            sceneRef.current = scene

            // 创建相机
            const camera = new THREE.PerspectiveCamera(
              45,
              width / height,
              0.1,
              1000
            )
            camera.position.set(5, 5, 5)
            cameraRef.current = camera

            // 创建WebGL渲染器
            const renderer = new THREE.WebGLRenderer({
              canvas,
              antialias: true,
              alpha: true
            })
            renderer.setSize(width, height, false)
            renderer.setPixelRatio(dpr)
            
            // 配置色彩管理
            if (renderer.outputEncoding !== undefined) {
              renderer.outputEncoding = THREE.sRGBEncoding
            }
            
            // 配置阴影映射
            renderer.shadowMap.enabled = true
            if (THREE.PCFSoftShadowMap) {
              renderer.shadowMap.type = THREE.PCFSoftShadowMap
            }
            
            rendererRef.current = renderer

            // 添加灯光
            setupLights(scene)

            // 添加地平面
            const planeGeometry = new THREE.PlaneGeometry(10, 10)
            const planeMaterial = new THREE.ShadowMaterial({ opacity: 0.2 })
            const plane = new THREE.Mesh(planeGeometry, planeMaterial)
            plane.rotation.x = -Math.PI / 2
            plane.position.y = -1
            plane.receiveShadow = true
            scene.add(plane)

            // 为小程序环境创建 GLTFLoader
            try {
              const GLTFLoaderModule = require('three/examples/jsm/loaders/GLTFLoader')
              GLTFLoader = GLTFLoaderModule.GLTFLoader
              console.log('小程序环境 GLTFLoader 创建成功')
            } catch (e) {
              console.warn('小程序环境 GLTFLoader 加载失败:', e)
            }

            // 加载3D模型
            loadModel(scene)

            // 渲染循环
            const animate = () => {
              canvas.requestAnimationFrame(animate)
              
              // 简单的自动旋转（小程序环境没有 OrbitControls）
              if (modelRef.current) {
                modelRef.current.rotation.y += 0.005
              }
              
              renderer.render(scene, camera)
            }
            animate()

            console.log('小程序 WebGLRenderer 初始化完成')
          })
      } catch (err) {
        console.error('小程序3D场景初始化失败:', err)
        setError('3D引擎初始化失败')
        setLoading(false)
      }
    }

    // 延迟执行，确保组件已挂载
    setTimeout(() => {
      initMiniprogram()
    }, 100)
    
    // 清理函数
    return () => {
      if (rendererRef.current) {
        rendererRef.current.dispose()
      }
    }
  }, [canvasId])

  // 设置灯光
  const setupLights = (scene: any) => {
    lightConfigs.forEach(config => {
      let light: any

      switch (config.type) {
        case 'ambient':
          light = new THREE.AmbientLight(config.color, config.intensity)
          break
        case 'directional':
          light = new THREE.DirectionalLight(config.color, config.intensity)
          if (config.position) {
            light.position.set(config.position.x, config.position.y, config.position.z)
          }
          light.castShadow = true
          break
        case 'point':
          light = new THREE.PointLight(config.color, config.intensity, 100)
          if (config.position) {
            light.position.set(config.position.x, config.position.y, config.position.z)
          }
          light.castShadow = true
          break
        case 'spot':
          light = new THREE.SpotLight(config.color, config.intensity)
          if (config.position) {
            light.position.set(config.position.x, config.position.y, config.position.z)
          }
          light.castShadow = true
          break
        default:
          light = new THREE.AmbientLight(config.color, config.intensity)
      }

      scene.add(light)
      lightsRef.current.set(config.id, light)
    })
  }

  // 加载3D模型
  const loadModel = async (scene: any) => {
    try {
      // 检查是否配置了模型URL
      if (!modelConfig.url) {
        console.warn('未配置模型URL，使用占位模型')
        loadPlaceholderModel(scene)
        return
      }

      // 获取实际的URL（可能是字符串或者包含default属性的对象）
      const modelUrl = typeof modelConfig.url === 'string' 
        ? modelConfig.url 
        : (modelConfig.url as any).default || modelConfig.url
      console.log('模型配置URL:', modelUrl, 'typeof:', typeof modelUrl)

      // 检查是否是 GLB/GLTF 格式
      const isGLTF = String(modelUrl).toLowerCase().match(/\.(glb|gltf)$/)
      
      if (isGLTF && GLTFLoader) {
        console.log('开始加载 GLB/GLTF 模型:', modelUrl)
        
        const loader = new GLTFLoader()
        const gltf = await new Promise<any>((resolve, reject) => {
          loader.load(
            modelUrl,
            (gltfScene: any) => {
              console.log('GLTF 模型加载成功')
              resolve(gltfScene)
            },
            (xhr: any) => {
              const progress = xhr.loaded / xhr.total * 100
              console.log('加载进度:', progress.toFixed(2) + '%')
            },
            (error: any) => {
              console.error('GLTF 加载失败:', error)
              reject(error)
            }
          )
        })

        const model = gltf.scene
        
        // 计算模型的边界盒，用于自动缩放和居中
        const box = new THREE.Box3().setFromObject(model)
        const center = box.getCenter(new THREE.Vector3())
        const size = box.getSize(new THREE.Vector3())
        
        // 计算最大尺寸
        const maxDim = Math.max(size.x, size.y, size.z)
        const scale = 2 / maxDim * modelConfig.scale
        
        // 将模型移到中心
        model.position.sub(center)
        
        // 应用缩放和配置
        model.scale.set(scale, scale, scale)
        model.position.add(new THREE.Vector3(
          modelConfig.position.x,
          modelConfig.position.y,
          modelConfig.position.z
        ))
        model.rotation.set(
          modelConfig.rotation.x,
          modelConfig.rotation.y,
          modelConfig.rotation.z
        )
        
        // 启用阴影
        model.traverse((child: any) => {
          if (child.isMesh) {
            child.castShadow = true
            child.receiveShadow = true
          }
        })
        
        scene.add(model)
        modelRef.current = model
        setLoading(false)
        
        console.log('GLB模型加载完成，尺寸:', size, '缩放:', scale)
      } else {
        // 不支持的格式使用占位模型
        console.log('不支持的模型格式或加载器未初始化，使用占位模型')
        loadPlaceholderModel(scene)
      }
    } catch (err) {
      console.error('加载模型失败:', err)
      setError('模型加载失败')
      setLoading(false)
      // 加载失败时使用占位模型
      loadPlaceholderModel(scene)
    }
  }

  // 加载占位模型（立方体）
  const loadPlaceholderModel = (scene: any) => {
    const geometry = new THREE.BoxGeometry(2, 2, 2)
    
    // 使用PBR材质（物理渲染）
    const material = new THREE.MeshStandardMaterial({
      color: 0xB8956A,       // 青铜色
      metalness: 0.3,        // 金属度
      roughness: 0.7,        // 粗糙度
      envMapIntensity: 1.0,
      flatShading: false,
      side: THREE.FrontSide
    })
    
    const cube = new THREE.Mesh(geometry, material)
    cube.castShadow = true
    cube.receiveShadow = true
    
    // 应用模型配置
    cube.scale.set(modelConfig.scale, modelConfig.scale, modelConfig.scale)
    cube.position.set(
      modelConfig.position.x,
      modelConfig.position.y,
      modelConfig.position.z
    )
    cube.rotation.set(
      modelConfig.rotation.x,
      modelConfig.rotation.y,
      modelConfig.rotation.z
    )

    scene.add(cube)
    modelRef.current = cube
    setLoading(false)
    
    console.log('占位模型加载完成')
  }

  // 切换灯光
  useEffect(() => {
    if (!selectedLightId) return

    lightsRef.current.forEach((light, id) => {
      // 除了环境光和选中的灯光，其他灯光降低强度
      if (id === selectedLightId || id === 'ambient') {
        light.intensity = lightConfigs.find(c => c.id === id)?.intensity || 1
      } else {
        light.intensity = 0.2
      }
    })
  }, [selectedLightId, lightConfigs])

  // 小程序环境渲染
  if (process.env.TARO_ENV === 'weapp') {
    return (
      <View className='model-viewer-container'>
        <View className='model-canvas-wrapper-mini'>
          <Canvas 
            type='webgl' 
            id={canvasId}
            className='model-canvas-mini'
          />
          {loading && (
            <View className='model-loading'>
              <View className='loading-spinner' />
              <View className='loading-text'>加载3D模型中...</View>
            </View>
          )}
          {error && (
            <View className='model-error'>
              <View className='error-text'>{error}</View>
            </View>
          )}
        </View>
        <View className='model-tips'>
          {/* 提示文字已隐藏 */}
        </View>
      </View>
    )
  }

  // H5环境渲染
  return (
    <View className='model-viewer-container'>
      <View className='model-canvas-wrapper' ref={containerRef as any}>
        {loading && (
          <View className='model-loading'>
            <View className='loading-spinner' />
            <View className='loading-text'>加载3D模型中...</View>
          </View>
        )}
        {error && (
          <View className='model-error'>
            <View className='error-text'>{error}</View>
          </View>
        )}
      </View>
      <View className='model-tips'>
        <View className='tip-item'>💡 拖拽旋转模型</View>
        <View className='tip-item'>🔍 双指缩放（鼠标滚轮）</View>
      </View>
    </View>
  )
}

export default ModelViewer

